package com.simafei.flow.core;

import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.map.MapUtil;
import com.simafei.flow.core.common.ExecStatus;
import com.simafei.flow.core.common.FlowStatus;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author fengpengju
 */
@Getter
@Builder
@Slf4j
@ToString
public class ExecutionContext {

    /**
     * 决策流ID
     */
    private String flowId;

    /**
     * 执行ID
     */
    private String execId;

    /**
     * 是否测试
     */
    private boolean test;

    /**
     * 流程状态
     */
    @Setter
    private volatile FlowStatus flowStatus;

    /**
     * 执行状态
     */
    @Setter
    private volatile ExecStatus execStatus;

    /**
     * 执行开始时间
     */
    @Builder.Default
    private Long startTime = System.currentTimeMillis();

    /**
     * 输入参数
     */
    private Map<String, Object> inputParams;

    /**
     * 节点执行结果
     */
    private Set<NodeResult> nodeResults;

    /**
     * 边执行结果
     */
    private Set<EdgeResult> edgeResults;

    /**
     * 执行监听器
     */
    private ExecutionListener executionListener;

    /**
     * 节点执行结果
     */
    @Builder.Default
    private Map<String, Map<String, Object>> attributes = new ConcurrentHashMap<>();

    public void collectResult(NodeResult nodeResult) {
        if (nodeResults == null) {
            // 使用同步集合类
            nodeResults = new ConcurrentHashSet<>();
        }
        nodeResults.add(nodeResult);
    }

    public void collectResult(EdgeResult edgeResult) {
        if (edgeResults == null) {
            // 使用同步集合类
            edgeResults = new ConcurrentHashSet<>();
        }
        edgeResults.add(edgeResult);
    }

    public void setAttribute(String nodeId, String key, Object value) {
        attributes.computeIfAbsent(nodeId, k -> MapUtil.newHashMap()).put(key, value);
    }

    public void setAttributes(String nodeId, Map<String, Object> map) {
        attributes.put(nodeId, map);
    }

    public Map<String, Object> getAttributes(String nodeId) {
        return attributes.get(nodeId);
    }

    public Object getAttribute(String nodeId, String key) {
        return attributes.get(nodeId).get(key);
    }
}
